/*
 * The TLB has 64 entries.
 */

#include <stdio.h>
#include <proto/exec.h>

typedef union {
   unsigned int value;
   struct {
      unsigned int epn: 22; // Effective page number
      unsigned int v: 1; // Valid
      unsigned int ts: 1; // Translation address space
      unsigned int size: 4; // Page size
      unsigned int tpar: 4; // Tag parity
  };
} TLB_W0_t;

// The 8-bit large field tid (Translation ID) is marked as part of the Word0
// but read from MMUCR[STID]

typedef union {
   unsigned int value;
   struct {
      unsigned int rpn: 22; // Real page number
      unsigned int par1: 2; // Parity for TLB word 1
      unsigned int reserved: 4; // Reserved
      unsigned int erpn: 4; // Extended Real Page Number
   };
} TLB_W1_t;

typedef union {
   unsigned int value;
   struct {
      unsigned int par2: 2; // Parity for TLB word 2
      unsigned int reserved0: 14; // Reserved
      unsigned int u0: 1; // User definable storage attribute 0
      unsigned int u1: 1; // User definable storage attribute 1
      unsigned int u2: 1; // User definable storage attribute 2
      unsigned int u3: 1; // User definable storage attribute 3
      unsigned int w: 1; // Write-through
      unsigned int i: 1; // Cache inhibited
      unsigned int m: 1; // Memory coherence required
      unsigned int g: 1; // Guarded
      unsigned int e: 1; // Endian
      unsigned int reserved1: 1; // Reserved
      unsigned int ux: 1; // User state execute enable
      unsigned int uw: 1; // User state write enable
      unsigned int ur: 1; // User state read enable
      unsigned int sx: 1; // Supervisor state execute enable
      unsigned int sw: 1; // Supervisor state write enable
      unsigned int sr: 1; // Supervisor state read enable
   };
} TLB_W2_t;

struct tlb_entry_t {
   TLB_W0_t w0;
   TLB_W1_t w1;
   TLB_W2_t w2;
   unsigned int stid;
};

extern void read_tlb_entry(int index, struct tlb_entry_t *entry);

void print_tlb_entry(int index, struct tlb_entry_t *e)
{
   printf("[%2d] EPN=0x%08x, V=%d, TS=%d, SIZE=%d, TPAR=%d\n", index, e->w0.epn, e->w0.v, e->w0.ts, e->w0.size, e->w0.tpar);
   printf("     RPN=0x%08x, ERPN=0x%08x, STID=0x%02x", e->w1.rpn, e->w1.erpn, e->stid & 0xff);
   printf("     U0=%d, U1=%d, U2=%d\n", e->w2.u0, e->w2.u1, e->w2.u2);
   printf("     W=%d, I=%d, M=%d, G=%d, E=%d, ", e->w2.w, e->w2.i, e->w2.m, e->w2.g, e->w2.e);
   printf("     UX=%d, UW=%d, UR=%d, SX=%d, SW=%d, SR=%d\n", e->w2.ux, e->w2.uw, e->w2.ur, e->w2.sx, e->w2.sw, e->w2.sr);
}

void print_all_tlb_entries()
{
   struct tlb_entry_t e[64];
   int i;
   int nb_valid = 0;
   int nb_ts0 = 0;
   int nb_guarded = 0;

   for (i=0 ; i<64 ; i++) {
      read_tlb_entry(i, &e[i]);
   }

   for (i=0 ; i<64 ; i++) {
      print_tlb_entry(i, &e[i]);
      if (e[i].w0.v == 1) {
         nb_valid++;
      }
      if (e[i].w0.ts == 0) {
         nb_ts0++;
      }
      if (e[i].w2.g == 1) {
         nb_guarded++;
      }
   }

   printf("nb_valid = %d\n", nb_valid);
   printf("nb_ts0 = %d\n", nb_ts0);
   printf("nb_guarded = %d\n", nb_guarded);
}

int main()
{
   APTR user_state;

   user_state = SuperState();
   if (user_state) {
#if 1
      print_all_tlb_entries();
#else
      int i;

      for (i=0 ; i<64 ; i++) {
         print_tlb_entry(i);
      }
#endif
      UserState(user_state);
   } else {
      printf("Failed to supervisor mode\n");
   }

   return 0;
}
